package ws.wsIOC.framework.context;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import ws.wsAOP.framework.aop.ProxyConfig;
import ws.wsAOP.framework.aop.WSAopProxy;
import ws.wsAOP.framework.aop.aopProxyFactory.WSDefaultAopProxyFactory;
import ws.wsIOC.framework.annotation.WSAutowired;
import ws.wsIOC.framework.annotation.WSResource;
import ws.wsIOC.framework.annotation.WSService;

public class WSApplicationContext {
	
	private Map<String,Object> instanceMapping = new ConcurrentHashMap<String,Object>();
	
	private List<String> packageNameList = new ArrayList<String>();
	
	private List<String> cacheClass = new ArrayList<String>();
	
	private WSAopProxy wSAopProxy;
	
	public WSApplicationContext(String location) throws Exception {
		//定位
		String xmlPath = this.getClass().getClassLoader().getResource(location).getPath();
		//载入
		doLoad(xmlPath);
		//注册
		doRegiest(packageNameList);
		//初始化
		doCreateBean(xmlPath);
		//注入
		populate();
	}
	
	public Object doGetBean(String BeanName) throws Exception{
		if(instanceMapping.isEmpty()){return null;}
		for(Entry<String,Object> entry : instanceMapping.entrySet()){
			//此处判断接口是否相等
			if(!entry.getKey().equals(Class.forName(BeanName).getInterfaces().getClass().getName())){
				Object target =  entry.getValue();
				//调用Aop
				return wSAopProxy.getProxy(target);
			}
		}
		return null;
	}
	
	public void populate(){
		if(instanceMapping.isEmpty()){return;}
		for(Entry<String,Object> entry :  instanceMapping.entrySet()){
			Field[] fields = entry.getValue().getClass().getDeclaredFields();
			
			for(Field field : fields){
				if(!field.isAnnotationPresent(WSAutowired.class)){continue;}
				
				WSAutowired wSAutowired = field.getAnnotation(WSAutowired.class);
			    String id = wSAutowired.value().trim();
			    if("".equals(id)){
			    	id = field.getType().getName();
			    }
			    field.setAccessible(true);
			    try {
					field.set(entry.getValue(), instanceMapping.get(id));
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	public void doCreateBean(String xmlPath) throws Exception {
		if(cacheClass.size() == 0){
			return;
		}
		List<ProxyConfig> proxyConfigList = new ArrayList<ProxyConfig>();
		ProxyConfig proxyConfig = new ProxyConfig(xmlPath);
		proxyConfigList.add(proxyConfig);
		try {
			for(String className : cacheClass){
			    Class<?> clazz = Class.forName(className);
			    if(clazz.isAnnotationPresent(WSService.class)){
			    	
			    	WSService wSService = clazz.getAnnotation(WSService.class);
			    	String id = wSService.value();
			    	
			    	Object obj = clazz.newInstance();
			    	
			    	if(!"".equals(id.trim())){
						instanceMapping.put(id, obj);
			    	}
			    	
			    	Class<?>[] interfaces = clazz.getInterfaces();
			    	for(Class<?> i : interfaces){
			    		instanceMapping.put(i.getName(), obj);
			    	}
			    	//初始化Aop
			    	wSAopProxy = new WSDefaultAopProxyFactory().createAopProxy(obj, proxyConfigList);
			    }else if(clazz.isAnnotationPresent(WSResource.class)){
			    	String id = firstLowwer(clazz.getSimpleName());
					instanceMapping.put(id, clazz.newInstance());
			    }
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		
	}
	
	public void doLoad(String xmlPath){
		DocumentBuilderFactory domfac=DocumentBuilderFactory.newInstance();
        try {
        	DocumentBuilder dombuilder=domfac.newDocumentBuilder();
			   InputStream is=new FileInputStream(xmlPath);
			   Document doc=dombuilder.parse(is);
			   Element root=doc.getDocumentElement();
			   NodeList dbinfo=root.getChildNodes();
			   if(dbinfo!=null){
				    for(int i=0;i<dbinfo.getLength();i++){
				    	Node db=dbinfo.item(i);
					       for(Node node=db.getFirstChild();node!=null;node=node.getNextSibling()){
					    	   if(db.getNodeType()==Node.ELEMENT_NODE){
							         if(db.getNodeName().equals("wsBean")){
							        	 packageNameList.add(node.getNodeValue());
							         }
						        }
					       }
				    }
			   }
        } catch (Exception e) {
            e.printStackTrace();
        }
	}	
	
	public void doRegiest(List<String> packageNameList){
		if(packageNameList == null || packageNameList.size() == 0) return ;
		for(String packageName : packageNameList){
			doRealRegiest(packageName);
		}
	}
	
	public void doRealRegiest(String packageName){
		String uu = "/" + packageName.replaceAll("\\.", "/");
		URL url = this.getClass().getResource(uu);
		File dir = new File(url.getFile());
		for (File file : dir.listFiles()) {
			if(file.isDirectory()){
				doRealRegiest(packageName+"." + file.getName());
			}else{
				cacheClass.add(packageName+"."+file.getName().replaceAll(".class", ""));
			} 
		}
	}
	
	
	public String firstLowwer(String className){
		char[] chars = className.toCharArray();
		chars[0] += 32;
		return String.valueOf(chars);
	}
	

}
